#include "StdAfx.h"
#include "Game.h"
#include "Deck.h"
#include "EventQ.h"
#include "TurnPlay.h"
#include "PlayInfo.h"
#include "Form1.h"
using namespace SHGame;
using namespace System::Collections::Generic;
using namespace System::Diagnostics;
Game::Game(Player^ leader)
{
	this->points = gcnew Dictionary<Player^, int>();
	gamecount = 0;
	this->lead = leader;
	{
		using namespace SHGame::Events;
		handler = gcnew EventHandler<PropChangeEvent^>(this, &Game::HandleNextPlay);
		EventQ::AddListener(TurnPlay::TurnNextEvent, handler);
		handlerEnd = gcnew EventHandler<PropChangeEvent^>(this, &Game::HandleEndTurn);
		EventQ::AddListener(TurnPlay::TurnEndEvent, handlerEnd);
		handlerStart = gcnew EventHandler<PropChangeEvent^>(this, &Game::HandleStartTurn);
		EventQ::AddListener(TurnPlay::TurnStartEvent, handlerStart);
		EventQ::AddListener("humanq", gcnew EventHandler<PropChangeEvent^>(this, &Game::HumanQ));

	}
	
	this->Reset();
}

Trick^ Game::getTrick() {
	return this->trick;
}

bool Game::hasTrick() {
	return this->trick != nullptr;
}

bool Game::play(Card^ c) {
	if (this->WantHumanBury() && TurnPlay::IsHumanTurn()) {
		this->HumanBury(c);
		return true;
	}
	if (!playing)
		return false;
	
	Player^ cur = TurnPlay::Current;
	if (c->Equals(Card::JackOfDiamonds)) {
		info->ShowedPartener = true;
		info[cur]->ShowedPartener = true;
	}
	
	System::Diagnostics::Debug::WriteLine("Playing for player: " + cur->ToString());
	if (!this->hasTrick()) {
		// add play info for the lead
		if (c->isTrump())
			info[cur]->TrumpLeads++;
		else
			info[cur]->FailLeads++;
		this->trick = gcnew Trick(cur, c);
	}
	else {
		// add info for playing a card
		Card^ lead = trick->getLead();
		if (lead->isTrump() && ! c->isTrump()) {
			info[cur]->ShowedNoTrump = true;
		}
	}
	this->trick->play(cur, c);
	this->getHand(cur)->remove(c);

	// NEW
	TurnPlay::MoveNext();
	this->pcs->Fire("repaint", nullptr, nullptr);
	return true;
}

/*
*******************************************************************************
Event Handling
*******************************************************************************
*/

void Game::HumanQ(Object^ src, PropChangeEvent^ pe) {
	if (this->hands[lead]->Size() < 1)
		// we're not playing, return
		return;
	if (! TurnPlay::ReadyForStart())
		return;
	TurnPlay::Start();
}

void Game::HandleNextPlay(Object^ src, PropChangeEvent^ pe) {
	if (!playing) {
		// we start asking people to pick.
		Diagnostics::Debug::WriteLine("Handling "+pe+" by asking for a new picker");
		this->askForPicker();
	} else {
		if (TurnPlay::GetHuman()->Equals(pe->New)) {
			Form1::Instance->postMsg("Click a card to play it.");
			return;
		}
	//this->getNextPlay();
	Player^ cur = TurnPlay::Current;
	Card^ play = this->playgens[cur]->getPlay(this->trick, this->getHand(cur), cur, this->info);
	this->play(play);
	}
}

void Game::HandleEndTurn(Object^ src, PropChangeEvent^ e)
{
	if (!playing) {
		// we're in pick/pass phase
		// everyone pases
		// this is a "leaster" situation
		Diagnostics::Debug::WriteLine("Done with Pick/Pass! _-_-_-_-_-_-_-_-_-_-_-_- ");
		TurnPlay::SetStart(lead);
		TurnPlay::Start();
		playing = true;
	} else {
		
		// set the current player to the owner of the trick: this player is the next leader
		Player^ owner = this->trick->getOwner();
		this->AddPoints(owner, trick->getPoints());
		// check if we're done with the game?
		if (this->hands[lead]->Size() < 1) {
			// game is over
			// add the last of the deck onto the trick if there are any left..
			if (this->deck->hasCards())
			{
				this->AddPoints(owner, deck->draw()->getValue());
				this->AddPoints(owner, deck->draw()->getValue());
			}
			pcs->Fire("gameover", nullptr, nullptr);
			return;
		} else {
			TurnPlay::SetStart(owner);
			this->pcs->Fire("repaint", nullptr, nullptr);
			this->pcs->Fire("reqhumanq", nullptr, nullptr);
		}
		// end if
	}
}

void Game::HandleStartTurn(Object^ src, PropChangeEvent^ e)
{
	if (!playing) {
		// we start asking people to pick.
		Diagnostics::Debug::WriteLine("Handling "+e+" by asking for a new picker");
		this->askForPicker();
	} else {
		Diagnostics::Debug::WriteLine("playing = true");
		this->trick = nullptr;

		if (TurnPlay::IsHumanTurn()) {
			Form1::Instance->postMsg("Click a card to lead.");
			this->pcs->Fire("repaint", nullptr, nullptr);
			return;
		}
		Player^ cur = TurnPlay::Current;
		Diagnostics::Debug::WriteLine("Playing for! ----------------------------- " + cur);
		Card^ play = this->playgens[cur]->getLead(this->getHand(cur), cur, info);
		this->play(play);
	}
}
/*
*******************************************************************************
    END
Event Handling
*******************************************************************************
*/

void Game::askForPicker() {
	if (TurnPlay::IsHumanTurn()) {
		pcs->Fire("human.pickpass", nullptr, nullptr);
		return;
	} else {
		Player^ cur = TurnPlay::Current;
		PlayGenerator^ pg = this->playgens[cur];
		CardSet^ hand = this->getHand(cur);
		bool picks = pg->wantPick(hand);
		if (!picks) {
			pcs->Fire("pass", cur, cur);
			
			Diagnostics::Debug::WriteLine("Passing! ----------------------------- " + cur);
			TurnPlay::MoveNext();
			return;
		} else {
			// add the cards to their hand
			this->Pickup(cur);
			array<Card^>^ putdown = pg->getBury(hand);
			hand->remove(putdown[0]);
			hand->remove(putdown[1]);
			// store the points they burried
			this->AddPoints(cur, putdown[0]->getValue());
			this->AddPoints(cur, putdown[1]->getValue());

			Diagnostics::Debug::WriteLine("Picking! ----------------------------- " + cur);
			pcs->Fire("pick", cur, cur);
			TurnPlay::Stop();
			Diagnostics::Debug::WriteLine("SETTING PLAYING TO TRUE " + cur);
			playing = true;
			TurnPlay::SetStart(lead);
			TurnPlay::Start();
		}
		
	}
	// end method
}
void Game::Pickup(Player^ cur)
{
	CardSet^ hand = this->getHand(cur);
	hand->add(deck->draw());
	hand->add(deck->draw());
	this->Picker = cur;
	Debug::Indent();
	Debug::WriteLine("Finding Partener", "GAME");
	for (int i = 0; i < 5; i++) {
		Player^ p = TurnPlay::GetPlayerAt(i);
		CardSet^ thand = this->getHand(p);
		Debug::WriteLine("Checking "+p+" for JD ... has " + thand->Size() + " cards.");
		if (thand->contains(Card::JackOfDiamonds)) {
			Debug::WriteLine("Found partener: " + p, "GAME");
			Partener = p;
		}
	}
	this->info = gcnew PlayInfo(this->Picker, this->Partener);
	Debug::Unindent();
}
void Game::HumanPick() {
	Player^ human = TurnPlay::GetHuman();
	this->Pickup(human);
	this->pcs->Fire("repaint", nullptr, nullptr);
	pcs->Fire("pick", human, human);
	wantHumanBury = true;
}
void Game::HumanPass() {
	TurnPlay::MoveNext();
}

/*
Determines if the given player at index i has played
*/
bool Game::hasPlayed(int i) {
	return this->getCard(i) != nullptr;
}
/*
Gets the card that belongs to the player
*/
Card^ Game::getCard(int i) {
	Player^ p = TurnPlay::GetPlayerAt(i);
		if (this->hasTrick()) {
			// see if we have a card in the trick
			if (this->trick->played(p))
				return this->trick->get(p);
		}
	return nullptr;
}
/*
Resets the game for the next game
*/
void Game::Reset() {
	Debug::WriteLine("Entering Game Reset Block");
	Debug::Indent();
	
	TurnPlay::Stop();
	this->lead = TurnPlay::GetPlayerAt(gamecount++ % 5);
	this->playing = false;
	this->Picker = nullptr;
	this->Partener = nullptr;
	this->trick = nullptr;
	this->PickerPoints = 0;
	this->DefenderPoints = 0;
	this->pcs = gcnew PropChangeSupport(this);
	this->hands = gcnew Dictionary<Player^, CardSet^>();
	this->playgens = gcnew Dictionary<Player^, PlayGenerator^>();
	// resets the point totals:
	this->points->Clear();
	
	deck = gcnew Deck();
	// set up hands
	for (int i = 0; i < 5; i++) {
		Player^ p = TurnPlay::GetPlayerAt(i);
		CardSet^ temp = gcnew CardSet();
		for (int i = 0; i < 6; i ++) {
			temp->add(deck->draw());
		}
		this->hands->Add(p, temp);
		this->playgens->Add(p, gcnew PlayGenerator());
	}
	TurnPlay::SetStart(lead);
	TurnPlay::Start();
	Debug::Unindent();
}

CardSet^ Game::getHand(Player^ p) {
	return this->hands[p];
}

/*
Returns the number of points taken by the given player
*/
int Game::GetPoints(Player^ p) {
	if (this->points->ContainsKey(p))
		return this->points[p];
	else
		return 0;
}

bool Game::TookTrick(Player^ p) {
	return this->points->ContainsKey(p);
}

/*
Adds the given points to the given player's total.
You can get the players total using GetPointss(p);
*/
void Game::AddPoints(Player^ p, int i) {
	this->info[p]->Points += i;
	if (this->points->ContainsKey(p)) {
		points[p] = points[p] + i;
	} else {
		points->Add(p, i);
	}
	if (IsPickTeam(p))
		PickerPoints += i;
	else
		DefenderPoints += i;
	Diagnostics::Debug::WriteLine("Adding " + i + " points to " + p + " ("+GetPoints(p)+")", "GAME");
}

/*
Determines if the given player is the picker or partener
*/
bool Game::IsPickTeam(Player^ p)
{
	return p->Equals(Picker) || p->Equals(Partener);
}

bool Game::WantHumanBury() {
	return this->wantHumanBury;
}

void Game::HumanBury(Card^ c) {
	if (!WantHumanBury())
		return;
	this->getHand(TurnPlay::GetHuman())->remove(c);
	this->AddPoints(TurnPlay::GetHuman(), c->getValue());
	pcs->Fire("repaint",nullptr,nullptr);
	if (this->getHand(TurnPlay::GetHuman())->Size() < 7) {
		wantHumanBury = false;
		TurnPlay::Stop();
			playing = true;
			TurnPlay::SetStart(lead);
			TurnPlay::Start();
	}
}